#include "PopupService.h"
#include "../../core/Impp.h"
#include "../../core/settings/Settings.h"

namespace Impp
{

IMPLEMENT_DYNAMIC_CLASS(StdPopupModule, iModule)

PopupService::PopupService() :
	dummyParentFrame(NULL),defaultPopupSize(160,60)
{
	Impp* impp = Impp::exemplar();
	popupsDB = impp->getDatabase()->getModule(wxT("Popups"));

	dummyParentFrame= new wxFrame(NULL,wxID_ANY,wxEmptyString);

	position = popupsDB.getIntValue(POPUPS_DB_POSITION,POPUP_POS_RIGHT_BOTTOM);

	enabled = popupsDB.getIntValue(POPUPS_DB_SHOW_GOES_ONLINE,1);
	goesOnline = popupsDB.getIntValue(POPUPS_DB_SHOW_GOES_ONLINE,1);
	goesOffline = popupsDB.getIntValue(POPUPS_DB_SHOW_GOES_OFFLINE,1);
	isTyping = popupsDB.getIntValue(POPUPS_DB_SHOW_ISTYPING,1);
	statusChanged = popupsDB.getIntValue(POPUPS_DB_SHOW_STATUS_CHANGED,0);
	messageIn = popupsDB.getIntValue(POPUPS_DB_SHOW_MESSAGE_IN,1);

	alpha = popupsDB.getIntValue(POPUPS_DB_POPUP_ALPHA,255);
	color = popupsDB.getIntValue(POPUPS_DB_POPUP_COLOR,1);

	colorGoesOnline = wxColor(164,255,140);
	colorGoesOffline = wxColor(255,161,161);
	colorIsTyping = wxColor(255,233,155);
	colorStatusChanged = wxColor(155,183,255);
	colorMessageIn = wxColor(255,214,155);

	Start(1000,false);
	impp->Connect(EVT_BUDDY_STATUS_CHANGED,StatusEventHandler(PopupService::onStatusChanged), NULL, this);
	impp->Connect(EVT_MESSAGE_IN,MessageEventHandler(PopupService::onMessageIn), NULL, this);
	impp->Connect(EVT_TYPING_NOTIFICATION,TypingNotificationEventHandler(PopupService::onTypingNotification), NULL, this);
	impp->Connect(EVT_SETTING_CHANGED,SettingChangedEventHandler(PopupService::onSettingChanged), NULL, this);

	SettingsPage* sPage = impp->getSettings()->createSettingsPage(popupsDB, wxT("Popups"));
	SettingsGroup* gShow = sPage->createSettingsGroup(wxT("show Popups.."));
	gShow->createCheckSetting(wxT("Enable Popups"),POPUPS_DB_ENABLED);
	gShow->createCheckSetting(wxT("Show a popup when a buddy goes online"),POPUPS_DB_SHOW_GOES_ONLINE);
	gShow->createCheckSetting(wxT("Show a popup when a buddy goes offline"),POPUPS_DB_SHOW_GOES_OFFLINE);
	gShow->createCheckSetting(wxT("Show a popup when a buddy is typing"),POPUPS_DB_SHOW_ISTYPING);
	gShow->createCheckSetting(wxT("Show a popup when a buddy changes his/her status"),POPUPS_DB_SHOW_STATUS_CHANGED);
	gShow->createCheckSetting(wxT("Show a popup when you received a message"),POPUPS_DB_SHOW_MESSAGE_IN);

	SettingsGroup* gPos = sPage->createSettingsGroup(wxT("Position:"));
	ChooseSetting* csPos = gPos->createChooseSetting(wxT("Position"), POPUPS_DB_POSITION);
	csPos->addChoice(wxT("1"), wxT("Left-Top"));
	csPos->addChoice(wxT("2"), wxT("Left-Bottom"));
	csPos->addChoice(wxT("3"), wxT("Right-Top"));
	csPos->addChoice(wxT("4"), wxT("Right-Bottom"));

}

PopupService::~PopupService()
{
	Impp* impp = Impp::exemplar();
	impp->Disconnect(EVT_BUDDY_STATUS_CHANGED,StatusEventHandler(PopupService::onStatusChanged), NULL, this);
	impp->Disconnect(EVT_MESSAGE_IN,MessageEventHandler(PopupService::onMessageIn), NULL, this);
	impp->Disconnect(EVT_TYPING_NOTIFICATION,TypingNotificationEventHandler(PopupService::onTypingNotification), NULL, this);
	impp->Disconnect(EVT_SETTING_CHANGED,SettingChangedEventHandler(PopupService::onSettingChanged), NULL, this);

	std::vector<Popup*>::iterator iter(popups.begin());
	while(iter != popups.end()) {
		Popup* popup = *iter;
		popup->Destroy();
		++iter;
	}

	wxDELETE(dummyParentFrame);
}

void PopupService::showPopup(Buddy* buddy,const wxString & txt,const wxColor & color, int time){
	if(enabled){
		int exsistsHight = 0;
		std::vector<Popup*>::iterator iter(popups.begin());
		for (; iter != popups.end(); ++iter) {
			exsistsHight+= (*iter)->GetSize().y;
		}
		wxPoint pos;
		wxRect screenSize = wxGetClientDisplayRect();
		switch (position) {
			case POPUP_POS_RIGHT_BOTTOM:
			{
				pos = wxPoint(screenSize.x+screenSize.width-defaultPopupSize.x,screenSize.y+screenSize.height-exsistsHight-defaultPopupSize.y);
				break;
			}
			case POPUP_POS_RIGHT_TOP:
			{
				pos = wxPoint(screenSize.x+screenSize.width-defaultPopupSize.x,screenSize.y+exsistsHight);
				break;
			}
			case POPUP_POS_LEFT_BOTTOM:
			{
				pos = wxPoint(screenSize.x,screenSize.y+screenSize.height-exsistsHight-defaultPopupSize.y);
				break;
			}
			case POPUP_POS_LEFT_TOP:
			{
				pos = wxPoint(screenSize.x,screenSize.y+exsistsHight);
				break;
			}
			default:
				wxLogDebug(wxT("PopupService::showPopup: Illegal Position"));
				break;
		}

		Popup* popup = new Popup(this,pos,defaultPopupSize,buddy,txt,color,time);
		popups.push_back(popup);
	}
}



void PopupService::showPopup(const wxString & txt,const wxColor & color, int time){
	showPopup(NULL,txt,color,time);
}

void PopupService::hidePopup(Popup* popup){
	std::vector<Popup*>::iterator iter(popups.begin());
	int hightToSub = 0;
	while(iter != popups.end()) {
		Popup* cur = *iter;

		if(cur==popup){
			hightToSub += cur->GetSize().GetHeight();
			cur->Destroy();
			iter = popups.erase(iter);
		}else{
			wxPoint pos = cur->GetPosition();

			switch (position) {
				case POPUP_POS_RIGHT_BOTTOM:
				case POPUP_POS_LEFT_BOTTOM:
				{
					cur->SetPosition(wxPoint(pos.x,pos.y+hightToSub));
					break;
				}
				case POPUP_POS_RIGHT_TOP:
				case POPUP_POS_LEFT_TOP:
				{
					cur->SetPosition(wxPoint(pos.x,pos.y-hightToSub));
					break;
				}
				default:
					wxLogDebug(wxT("PopupService::Notify: Illegal Position"));
					break;
			}
			 ++iter;
		}

	}
}


void PopupService::setPopupPosition(const PopupPosition & pos){
	position = pos;
	popupsDB.setIntValue(wxT("position"), (int)pos);
}

void PopupService::Notify(){
	time_t now = wxDateTime::GetTimeNow();
	int hightToSub = 0;

	std::vector<Popup*>::iterator iter(popups.begin());
	while(iter != popups.end()) {
		Popup* cur = *iter;

		if(cur->isTimedOut(now)){
			hightToSub += cur->GetSize().GetHeight();
			cur->Destroy();
			iter = popups.erase(iter);
		}else{
			wxPoint pos = cur->GetPosition();

			switch (position) {
				case POPUP_POS_RIGHT_BOTTOM:
				case POPUP_POS_LEFT_BOTTOM:
				{
					cur->SetPosition(wxPoint(pos.x,pos.y+hightToSub));
					break;
				}
				case POPUP_POS_RIGHT_TOP:
				case POPUP_POS_LEFT_TOP:
				{
					cur->SetPosition(wxPoint(pos.x,pos.y-hightToSub));
					break;
				}
				default:
					wxLogDebug(wxT("PopupService::Notify: Illegal Position"));
					break;
			}
			 ++iter;
		}

	}
}


void PopupService::showGoingOnlinePopup(Buddy* buddy,const Status & oldStatus){
	if(goesOnline){
		wxString msg = buddy->getName();
		msg << wxT(" is now Online");
		showPopup(buddy,msg,colorGoesOnline,2);
	}
}
void PopupService::showGoingOfflinePopup(Buddy* buddy,const Status & oldStatus){
	if(goesOffline){
		wxString msg = buddy->getName();
		msg << wxT(" is now Offline");
		showPopup(buddy,msg,colorGoesOffline,2);
	}
}
void PopupService::showIsTypingPopup(Buddy* buddy){
	if(isTyping){
		wxString msg = buddy->getName();
		msg << wxT(" is typing a Message");
		showPopup(buddy,msg,colorIsTyping,3);
	}
}
void PopupService::showStatusChangedPopup(Buddy* buddy, const Status & newStatus, const Status & oldStatus){
	if(isTyping){
		wxString msg = buddy->getName();
		msg << wxT(" has changed his/her status to ");
		msg << statusToString(newStatus);
		showPopup(buddy,msg,colorStatusChanged,2);
	}
}
void PopupService::showMessageInPopup(Buddy* buddy, const wxString & message){
	if(messageIn){
		wxString msg = buddy->getName();
		msg << wxT(": ");
		msg << message;
		showPopup(buddy,msg,colorMessageIn,4);
	}
}

void PopupService::setEnabled(bool en){
	enabled = en;
	popupsDB.setIntValue(POPUPS_DB_ENABLED,en);
}

void PopupService::setShowPopupOnGoingOnline(bool show){
	goesOnline=show;
	popupsDB.setIntValue(POPUPS_DB_SHOW_GOES_ONLINE,show);
}
void PopupService::setShowPopupOnGoingOffline(bool show){
	goesOffline=show;
	popupsDB.setIntValue(POPUPS_DB_SHOW_GOES_OFFLINE,show);
}
void PopupService::setShowPopupIsTyping(bool show){
	isTyping=show;
	popupsDB.setIntValue(POPUPS_DB_SHOW_ISTYPING,show);
}
void PopupService::setShowPopupOnStatusChanged(bool show){
	statusChanged=show;
	popupsDB.setIntValue(POPUPS_DB_SHOW_STATUS_CHANGED,show);
}
void PopupService::setShowPopupOnMessageIn(bool show){
	messageIn=show;
	popupsDB.setIntValue(POPUPS_DB_SHOW_MESSAGE_IN,show);
}

wxFrame* PopupService::getDummyFrame(){
	return dummyParentFrame;
}

void PopupService::onStatusChanged(StatusEvent & event){
	event.Skip();

	if(event.getStatusConnectionType() == STATUS_EVENT_SELF_CONNECTED && event.isStatusDifferent(false)){
		Buddy* buddy = event.getBuddy();
		Status oldStatus = event.getOldStatus();
		Status newStatus = event.getNewStatus();

		switch (event.getStatusEventType()) {
			case STATUS_EVENT_BUDDY_SIGNED_ON:
				showGoingOnlinePopup(buddy,oldStatus);
				break;
			case STATUS_EVENT_BUDDY_SIGNED_OFF:
				showGoingOfflinePopup(buddy,oldStatus);
				break;
			case STATUS_EVENT_BUDDY_STATUS_CHANGED:
				showStatusChangedPopup(buddy,newStatus,oldStatus);
				break;
		}
	}
}

void PopupService::onMessageIn(MessageEvent & event){
	event.Skip();
	showMessageInPopup(event.getBuddy(),event.getMessage());
}

void PopupService::onTypingNotification(TypingNotificationEvent & event){
	event.Skip();
	if(event.getState()==TYPING_STARTED){
		showIsTypingPopup(event.getSender());
	}
}

void PopupService::onSettingChanged(SettingChangedEvent & event){
	if(event.getModule() == popupsDB){

		wxString settingName = event.getSettingName();

		if(settingName == POPUPS_DB_ENABLED){
			setEnabled(event.IsChecked());
		}else if(settingName == POPUPS_DB_POSITION){
			long int pos;
			event.GetString().ToLong(&pos);
			setPopupPosition((PopupPosition)pos);
		}else if(settingName == POPUPS_DB_SHOW_GOES_ONLINE){
			setShowPopupOnGoingOnline(event.IsChecked());
		}else if(settingName == POPUPS_DB_SHOW_GOES_OFFLINE){
			setShowPopupOnGoingOffline(event.IsChecked());
		}else if(settingName == POPUPS_DB_SHOW_ISTYPING){
			setShowPopupIsTyping(event.IsChecked());
		}else if(settingName == POPUPS_DB_SHOW_MESSAGE_IN){
			setShowPopupOnMessageIn(event.IsChecked());
		}else if(settingName == POPUPS_DB_SHOW_STATUS_CHANGED){
			setShowPopupOnStatusChanged(event.IsChecked());
		}else{
			event.Skip();
		}
	}else{
		event.Skip();
	}
}

bool PopupService::useColor(){
	return color;
}
int PopupService::getAlpha(){
	return alpha;
}

}

